package com.wqc.aop;

import com.wqc.annotation.DictField;
import com.wqc.common.pojo.ApiResponse;
import com.wqc.common.util.DictUtils;
import com.wqc.common.util.JacksonUtil;
import com.wqc.common.util.ReflectionUtils;
import com.wqc.common.constant.CommonConstants;
import com.wqc.common.enums.ResultCode;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Aspect
@Component
public class DictDataAspect {

    private final Logger LOGGER = LoggerFactory.getLogger(DictDataAspect.class);



    @Pointcut("execution(* com.wqc.web..*Controller.*(..))")
    public void fillDictField(){
    }

    @AfterReturning(value="fillDictField()", argNames="joinPoint,retVal", returning="retVal")
    public Object after(JoinPoint joinPoint, Object retVal)
            throws Throwable
    {
        LOGGER.debug("ExceptionResolverAspect after begin");
        long time_start = System.currentTimeMillis();
        Object object = afterReturnExcute(joinPoint, retVal);
        long time_end = System.currentTimeMillis();
        LOGGER.info("转换数据字典耗时: " + (time_end - time_start) + "ms");

        return object;
    }

    private Object afterReturnExcute(JoinPoint joinPoint, Object retVal)
            throws Throwable
    {
        if (retVal instanceof ApiResponse) {
            ApiResponse response = (ApiResponse)retVal;

            Integer code = response.getCode();
            if (code.intValue() == ResultCode.SUCCESS.getCode()) {
                response.setMessage(ResultCode.SUCCESS.getDesc());
            }
            Object data = response.getData();

            if (data instanceof List)
            {
                List<Object> list = (List)data;
                for (Object object : list) {
                    if (ReflectionUtils.isBaseType(object.getClass())) {
                        break;
                    }
                    dictDataFormat(object);
                }
            }
            else
            {
                if ((data != null) && (!(ReflectionUtils.isBaseType(data.getClass())))) {
                    dictDataFormat(data);
                }
            }
        }
        return retVal;
    }

    private void dictDataFormat(Object obj)
    {
        if (obj == null) {
            return;
        }
        try
        {
            if (obj instanceof List)
            {
                List<Object> list = (List)obj;
                for (Object object : list) {
                    if (ReflectionUtils.isBaseType(object.getClass())) {
                        break;
                    }
                    dictDataFormat(object);
                }
            }
            if (obj instanceof Map) {
                dictDataFormatForMap((Map)obj);
                return;
            }
            Field[] fields = ReflectionUtils.getAccessibleFields(obj);
            for (Field f : fields) {
                if (f.getName().equals("dtos")) {
                    System.out.println(f);
                }

                if ((!(ReflectionUtils.isBaseType(f.getType()))) &&
                        (f.getType() != Map.class)) {
                    dictDataFormat(ReflectionUtils.getFieldValue(obj, f.getName()));
                }

                DictField meta = (DictField)f.getAnnotation(DictField.class);
                if (meta != null) {
                    String key = (String)ReflectionUtils.getFieldValue(obj, f.getName());
                    if ((key == null) || ((key.contains("key")) && (key.contains("value")) && (key.contains("desc")))) {
                        continue;
                    }
                    String[] keys = key.split(",");
                    List list = new ArrayList();
                    for (String key1 : keys) {
                        String value = DictUtils.getDictValue(key1);
                        String desc = DictUtils.getDictDesc(key1);
                        Map map = new HashMap();
                        map.put("key", key1);
                        map.put("value", value);
                        if (!StringUtils.isEmpty(desc)) {
                            map.put("desc", desc);
                        }
                        list.add(map);
                    }
                    String jValue = JacksonUtil.toJSON(list);
                    ReflectionUtils.setFieldValue(obj, f.getName(), jValue);
                }
            }
        }
        catch (Exception e) {
            LOGGER.error("dictDataFormat error..", e);
            return;
        }
    }

    private void dictDataFormatForMap(Map map)
    {
        if (!(map.containsKey(CommonConstants.DIC_FIELD_NAMES_FLAG))) {
            return;
        }

        Object o = map.get(CommonConstants.DIC_FIELD_NAMES_FLAG);
        if ((null == o) || (!(o instanceof List))) {
            return;
        }
        List dicFieldNames = (List)o;
        if (ObjectUtils.isEmpty(dicFieldNames)) {
            return;
        }
        for (int i = 0; i < dicFieldNames.size(); ++i) {
            String dicFieldName = (String)dicFieldNames.get(i);
            String typeAndKey = (String)map.get(dicFieldName);
            if (ObjectUtils.isEmpty(typeAndKey)) {
                continue;
            }
            map.put(dicFieldName, getDicArrayStr(typeAndKey));
        }
    }

    private String getDicArrayStr(String typeAndKey)
    {
        List dicList = new ArrayList();
        String value = DictUtils.getDictValue(typeAndKey);
        String desc = DictUtils.getDictDesc(typeAndKey);
        Map dicMap = new HashMap();
        dicMap.put("key", typeAndKey);
        dicMap.put("value", value);
        if (!ObjectUtils.isEmpty(desc)) {
            dicMap.put("desc", desc);
        }
        dicList.add(dicMap);
        return JacksonUtil.toJSON(dicList);
    }
}
